feat: support claude-code 2.1.245 esm-chunked native format - #336
Conversation
Upstream 2.1.245 switched from a single CJS-wrapped bundle to Bun code-splitting into ESM chunks (StandaloneModuleGraph container with 1387 modules). Add a parallel esm-chunked execution path that extracts modules to a process-owned directory and runs them under plain Node.js via a custom ESM loader (bunfs-esm-loader.mjs), with guards for child_process/vm access (bunfs-child-process-guard.mjs, bunfs-vm-guard.mjs) and a ws no-op stub matching the existing legacy-cjs behavior (bunfs-ws-stub.mjs). The legacy-cjs path (single-bundle versions) is unchanged; format is auto-detected from the entry module's content. Reviewed via G1 (design), G3 (coding review), G4 (verification) — all Go with no blockers.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 91569eab23
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const require = createRequire(import.meta.url); | ||
| const realChildProcess = require('node:child_process'); | ||
| const { createGuardedChildProcess } = require('./native-update-guard.js'); | ||
| const guarded = createGuardedChildProcess(realChildProcess, (v) => process.stderr.write(v)); |
There was a problem hiding this comment.
Preserve Termux URL rewriting in the ESM child-process guard
When the ESM CLI opens a browser during authentication or another URL-opening flow, this guard forwards xdg-open unchanged to the real child-process module, but Termux provides termux-open-url instead. The legacy path explicitly rewrites xdg-open in both spawn and spawnSync, and the launcher still requires termux-open-url; therefore the new esm-chunked path regresses those flows unless the same rewrite is applied before creating the guarded methods.
Useful? React with 👍 / 👎.
| const { register } = require('node:module'); | ||
| const { pathToFileURL } = require('node:url'); | ||
|
|
||
| const { ownedDir, entryRelPath } = prepareProcessOwnedDir(sourceBin, workdir); |
There was a problem hiding this comment.
Remove each extracted ESM directory when its process exits
Every ESM invocation creates a new directory containing all extracted non-NAPI modules, but neither bootstrap registers an exit handler to remove ownedDir. The only cleanup occurs on a later invocation, and cleanupStaleOwnedDirs deliberately retains dead-process directories younger than 24 hours, so repeated short-lived calls such as claude -p, --version, or --help accumulate complete extracted bundles and can exhaust the limited storage commonly available in Termux. Register synchronous exit cleanup for the current directory while retaining stale cleanup for crashes.
Useful? React with 👍 / 👎.
- SC2155: Separate local declaration and assignment for cmd_start, cmd_end, stdout_lines, stderr_lines - SC2034: Remove unused expected_code variable from case statement in report generation loop Co-Authored-By: Claude Sonnet 5 <[email protected]>
Summary
Upstream claude-code 2.1.245 replaced the single CJS-wrapped bundle with Bun code-splitting into ESM chunks (StandaloneModuleGraph container with 1387 modules). This change adds a parallel
esm-chunkedexecution path that:bunfs-esm-loader.mjs)bunfs-child-process-guard.mjs,bunfs-vm-guard.mjs)bunfs-ws-stub.mjs) and YAML shim (bunfs-yaml-shim.mjs)The legacy CJS path (single-bundle versions) remains unchanged. Format is auto-detected from the entry module's content signature.
Test plan
🤖 Generated by Claude Code